/*
** $Id: crypter.c 35 2014-10-22 09:31:02Z chupin007@gmail.com $
** $HeadURL: http://bapps.googlecode.com/svn/trunk/src/enc/src/crypter.c $
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

int main( int argc, char **argv ) {

int keylen;
char key[256];
FILE *fp;
char c;
char *command, *keyfile;
int  cols[256];
int  typs[256];
char buff[32767], crypted[32767];
int ncol, cpos, i, nfld, bpos, len;
char *skipTitle;
unsigned nline=0;
int numRequiredFields;

  if( argc < 6 ) {
    fprintf( stderr, "wrong number of arguments\n" );
    exit( 1 );
  }

  skipTitle = argv[1];
  sscanf( argv[2], "%d", &numRequiredFields );
  numRequiredFields--;

  keyfile = argv[3];
  command = argv[4];
  if( strcmp( command, "encrypt" ) != 0 && strcmp( command, "decrypt" ) != 0  ) {
    fprintf( stderr, "wrong command\n" );
    exit( 1 );
  }

  ncol=0;
  for( i=5; i < argc; i++ ) {
    typs[ncol] = argv[i][0];
    if( typs[ncol] != 'h' && typs[ncol] != 'i' ) {
      fprintf( stderr, "incorrect encryption type\n" );
      exit( 1 );
    }
    sscanf( argv[i]+1, "%d", cols+ncol );
    if( ncol > 0 && cols[ncol] <= cols[ncol-1] || cols[ncol] < 1 ) {
      fprintf( stderr, "wrong columns order or value\n" );
      exit( 1 );
    }
    ncol++;
    if( ncol > 255 ) {
      fprintf( stderr, "too many columns to encrypt\n" );
      exit( 1 );
    }
  }
  for( i = 0; i < ncol; i++ ) cols[i] = cols[i] - 1;


  fp = fopen( keyfile, "r+" );
  if( fp == NULL ) {
    fprintf( stderr, "cannot read key file: %s\n", keyfile );
    exit( 1 );
  }
  keylen = fread( key, 1, sizeof( key ), fp );
  key[keylen] = '\0';

  if( memchr( key, '\n', keylen ) ) {
    fprintf( stderr, "new line found in key: len=%d, %s\n", keylen, key );
    exit( 1 );
  }

  crypterInit( strcmp( command, "encrypt" ), key );

  nfld=0;
  cpos=0;
  bpos=0;
  while( (c = getchar()) != EOF ) {
    if( c == '\t' || c == '\n' ) {
      buff[bpos] = '\0';
      if( ( nline > 0 || strcmp(skipTitle,"Y") ) && nfld == cols[cpos] ) {
        /* field conversion */
        if( strcmp( command, "encrypt" ) == 0 ) {
          len = strlen( buff );
          if( len > 0 ) {
            if( typs[cpos] == 'i' ) {
              unsigned char ipbytes[16];
              parseIPV4( buff, ipbytes );
              len = 4;
              {
                len = crypterEncrypt( nfld, ipbytes, crypted, len );
              }
              printf("%d.%d.%d.%d", (unsigned char ) crypted[0], (unsigned char ) crypted[1], (unsigned char ) crypted[2], (unsigned char ) crypted[3]);
            } else {
              {
              len = crypterEncrypt( nfld, buff, crypted, len );
              }
              for( i = 0; i < len; i++ ) {
                printf("%02x", (unsigned char ) crypted[i]);
              }
            }
          }
        } else if( strcmp( command, "decrypt" ) == 0 ) {
          int newval;
          char *ptrCrypted = crypted;
          len = strlen( buff );
          if( len > 0 ) {
            if( typs[cpos] == 'i' ) {
              unsigned char ipbytes[16];
              parseIPV4( buff, ipbytes );
              len = 4;
              {
                len = crypterDecrypt( nfld, ipbytes, buff, len );
              }
              buff[len] = '\0';
              printf("%d.%d.%d.%d", (unsigned char ) buff[0], (unsigned char ) buff[1], (unsigned char ) buff[2], (unsigned char ) buff[3]);
            } else {
              if( len%2 != 0 ) {
                fprintf( stderr, "bad hexadecimal string found1: %s\n", buff );
                exit( 1 );
              }
              for( i = 0; i < len; i+=2 ) {
                int val1 = (unsigned char) buff[i];
                int val2 = (unsigned char) buff[i+1];
                if( val1 >= '0' && val1 <= '9' ) val1 = val1 - '0';
                else if( val1 >= 'a' && val1 <= 'f' ) val1 = val1 - 'a' + 10;
                else {
                  fprintf( stderr, "bad hexadecimal string found2 (%c%c): %s\n", val1, val2, buff );
                  exit( 1 );
                }
                if( val2 >= '0' && val2 <= '9' ) val2 = val2 - '0';
                else if( val2 >= 'a' && val2 <= 'f' ) val2 = val2 - 'a' + 10;
                else {
                  fprintf( stderr, "bad hexadecimal string found3 (%c%c): %s\n", val1, val2, buff );
                  exit( 1 );
                }
                newval = 16 * val1 + val2;
                *ptrCrypted = (unsigned char) newval;
                ptrCrypted++;
              }
              len = len/2;
              {
                len = crypterDecrypt( nfld, crypted, buff, len );
              }
              buff[len] = '\0';
              printf("%s", buff );
            }
          }
        } else {
          fprintf( stderr, "unexpected command\n" );
          exit( 1 );
        }
        cpos++;
      } else {
        /* no conversion */
        printf( "%s", buff );
      }
      putchar( c );
      bpos = 0;
      if(  c == '\n' ) {
        if( nfld != numRequiredFields ) {
          fprintf( stderr, "wrong number of fields. found:%d, required:%d, line:%d\n", nfld+1, numRequiredFields+1, nline+1 );
          exit( 1 );
        }
        cpos = 0;
        nfld = 0;
        nline++;
      } else {
        nfld++;
      }
    } else {
      if( bpos >= 8000 ) {
        fprintf( stderr, "length of field #%d exeeded 8000 characters, line:%d\n", nfld+1, nline+1 );
        exit( 1 );
      }
      buff[bpos++] = c;
    }
  }
  if( nfld != 0 || cpos != 0 || nfld != 0 ) {
    fprintf( stderr, "incomplete last line\n" );
    exit( 1 );
  }
  exit(0);
}
